package com.manda.smart.hub.common.event;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.GlobalThreadPool;
import cn.hutool.core.util.TypeUtil;
import com.manda.smart.hub.common.comparator.Sortable;
import lombok.Getter;

import java.util.*;
import java.util.concurrent.Executor;

/**
 * 事件发布者
 *
 * @author hongda.li
 */
@Getter
public final class EventPublisher implements Sortable<EventListener<?>> {
    /**
     * 监听器容器
     * 键：监听器需监听的事件类型
     * 值：事件对应所有监听器集合
     */
    private final Map<Class<?>, List<EventListener<?>>> eventListenerMap;

    /**
     * 构造一个监听器发布者
     *
     * @param eventListenerList 监听器集合
     */
    public EventPublisher(List<EventListener<?>> eventListenerList) {
        Objects.requireNonNull(eventListenerList);
        this.eventListenerMap = HashMap.newHashMap(8);
        for (EventListener<?> eventListener : eventListenerList) {
            Class<?> argument = (Class<?>) TypeUtil.getTypeArgument(eventListener.getClass());
            eventListenerMap.computeIfAbsent(argument, key -> new ArrayList<>()).add(eventListener);
        }
    }

    @Override
    public void sort(Comparator<EventListener<?>> comparator) {
        Objects.requireNonNull(comparator);
        this.eventListenerMap.forEach((key, value) -> value.sort(comparator));
    }

    /**
     * 发布事件
     * 监听器按顺序执行，若未调用过 sort() 方法，则按加入的原始顺序执行
     *
     * @param event 事件
     * @param <E>   事件泛型
     */
    @SuppressWarnings("unchecked")
    public <E extends Event> void publishEvent(E event) {
        Objects.requireNonNull(event);
        List<EventListener<?>> listeners = eventListenerMap.get(event.getClass());
        if (CollUtil.isEmpty(listeners)) {
            return;
        }
        listeners.forEach(listener -> ((EventListener<E>) listener).doListen(event));
    }

    /**
     * 异步发布事件
     * 监听器的执行顺序无法得到保证
     *
     * @param event 事件
     * @param <E>   事件泛型
     */
    public <E extends Event> void publishAsyncEvent(E event) {
        this.publishAsyncEvent(event, GlobalThreadPool.getExecutor());
    }

    /**
     * 异步发布事件
     * 监听器的执行顺序无法得到保证
     * 支持指定异步执行的线程池
     *
     * @param event    事件
     * @param executor 线程池
     * @param <E>      事件泛型
     */
    @SuppressWarnings("unchecked")
    public <E extends Event> void publishAsyncEvent(E event, Executor executor) {
        Objects.requireNonNull(event);
        Objects.requireNonNull(executor);
        List<EventListener<?>> listeners = eventListenerMap.get(event.getClass());
        if (CollUtil.isEmpty(listeners)) {
            return;
        }
        listeners.forEach(listener -> executor.execute(() -> ((EventListener<E>) listener).doListen(event)));
    }
}
